#!/bin/bash

# Zenith Mind Pro - Docker 环境一键部署脚本
# 包含 Seata、Prometheus + Grafana、ELK Stack

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

log_debug() {
    echo -e "${BLUE}[DEBUG]${NC} $1"
}

# 检查 Docker 和 Docker Compose
check_docker() {
    log_info "检查 Docker 环境..."
    
    if ! command -v docker &> /dev/null; then
        log_error "Docker 未安装，请先安装 Docker"
        exit 1
    fi
    
    if ! docker compose version &> /dev/null; then
        log_error "Docker Compose 未安装或版本过低，请升级到最新版本"
        exit 1
    fi
    
    # 检查 Docker 守护进程
    if ! docker info &> /dev/null; then
        log_error "Docker 守护进程未运行，请启动 Docker"
        exit 1
    fi
    
    log_info "Docker 环境检查通过"
}

# 检查端口占用
check_ports() {
    log_info "检查端口占用情况..."
    
    local ports=(3306 6379 8848 9090 3000 9200 5601 5000 8080 8091 9000 9001 9002 2078)
    local occupied_ports=()
    
    for port in "${ports[@]}"; do
        if netstat -tuln 2>/dev/null | grep -q ":$port " || ss -tuln 2>/dev/null | grep -q ":$port "; then
            occupied_ports+=($port)
        fi
    done
    
    if [ ${#occupied_ports[@]} -gt 0 ]; then
        log_warn "以下端口已被占用: ${occupied_ports[*]}"
        log_warn "这可能会导致部署失败，建议先关闭占用这些端口的服务"
        read -p "是否继续部署? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            log_info "取消部署"
            exit 0
        fi
    else
        log_info "端口检查通过，无冲突"
    fi
}

# 创建必要目录
create_directories() {
    log_info "创建必要的目录结构..."
    
    local dirs=(
        "seata/logs"
        "prometheus"
        "grafana/dashboards"
        "grafana/provisioning/datasources"
        "grafana/provisioning/dashboards"
        "logstash/pipeline"
        "logstash/config"
        "logs"
    )
    
    for dir in "${dirs[@]}"; do
        if [ ! -d "$dir" ]; then
            mkdir -p "$dir"
            log_debug "创建目录: $dir"
        fi
    done
    
    log_info "目录结构创建完成"
}

# 构建镜像
build_images() {
    log_info "构建项目镜像..."
    
    # 编译项目
    log_info "编译项目..."
    mvn clean package -DskipTests
    
    # 构建各个服务镜像
    local services=("zenith-gateway" "zenith-user-service" "zenith-api-service" "zenith-edu-service" "zenith-article-service"
    
    for service in "${services[@]}"; do
        if [ -f "$service/Dockerfile" ]; then
            log_info "构建 $service 镜像..."
            docker build -t "zenith/$service:latest" "$service/"
        else
            log_warn "$service/Dockerfile 不存在，跳过构建"
        fi
    done
    
    log_info "镜像构建完成"
}

# 启动基础设施服务
start_infrastructure() {
    log_info "启动基础设施服务..."
    
    # 先启动数据库和注册中心
    docker compose up -d mysql redis nacos
    
    log_info "等待基础设施服务启动..."
    sleep 30
    
    # 检查 MySQL 连接
    log_info "等待 MySQL 准备就绪..."
    local max_attempts=30
    local attempt=0
    
    while [ $attempt -lt $max_attempts ]; do
        if docker compose exec mysql mysqladmin ping -h localhost --silent; then
            log_info "MySQL 已就绪"
            break
        fi
        ((attempt++))
        log_debug "等待 MySQL 启动... ($attempt/$max_attempts)"
        sleep 5
    done
    
    if [ $attempt -eq $max_attempts ]; then
        log_error "MySQL 启动超时"
        exit 1
    fi
    
    # 检查 Nacos 连接
    log_info "等待 Nacos 准备就绪..."
    attempt=0
    
    while [ $attempt -lt $max_attempts ]; do
        if curl -f -s http://localhost:8848/nacos/actuator/health > /dev/null 2>&1; then
            log_info "Nacos 已就绪"
            break
        fi
        ((attempt++))
        log_debug "等待 Nacos 启动... ($attempt/$max_attempts)"
        sleep 5
    done
    
    if [ $attempt -eq $max_attempts ]; then
        log_error "Nacos 启动超时"
        exit 1
    fi
    
    log_info "基础设施服务启动完成"
}

# 启动监控服务
start_monitoring() {
    log_info "启动监控服务..."
    
    docker compose up -d prometheus grafana
    
    log_info "等待监控服务启动..."
    sleep 15
    
    # 检查 Prometheus
    local attempt=0
    local max_attempts=20
    
    while [ $attempt -lt $max_attempts ]; do
        if curl -f -s http://localhost:9090/-/ready > /dev/null 2>&1; then
            log_info "Prometheus 已就绪"
            break
        fi
        ((attempt++))
        log_debug "等待 Prometheus 启动... ($attempt/$max_attempts)"
        sleep 3
    done
    
    # 检查 Grafana
    attempt=0
    while [ $attempt -lt $max_attempts ]; do
        if curl -f -s http://localhost:3000/api/health > /dev/null 2>&1; then
            log_info "Grafana 已就绪"
            break
        fi
        ((attempt++))
        log_debug "等待 Grafana 启动... ($attempt/$max_attempts)"
        sleep 3
    done
    
    log_info "监控服务启动完成"
}

# 启动日志服务
start_logging() {
    log_info "启动日志服务..."
    
    docker compose up -d elasticsearch logstash kibana
    
    log_info "等待日志服务启动..."
    sleep 30
    
    # 检查 Elasticsearch
    local attempt=0
    local max_attempts=30
    
    while [ $attempt -lt $max_attempts ]; do
        if curl -f -s http://localhost:9200/_cluster/health > /dev/null 2>&1; then
            log_info "Elasticsearch 已就绪"
            break
        fi
        ((attempt++))
        log_debug "等待 Elasticsearch 启动... ($attempt/$max_attempts)"
        sleep 5
    done
    
    # 检查 Kibana
    attempt=0
    while [ $attempt -lt $max_attempts ]; do
        if curl -f -s http://localhost:5601/api/status > /dev/null 2>&1; then
            log_info "Kibana 已就绪"
            break
        fi
        ((attempt++))
        log_debug "等待 Kibana 启动... ($attempt/$max_attempts)"
        sleep 5
    done
    
    log_info "日志服务启动完成"
}

# 启动分布式事务服务
start_seata() {
    log_info "启动 Seata 分布式事务服务..."
    
    docker compose up -d seata-server
    
    log_info "等待 Seata 服务启动..."
    sleep 20
    
    # 检查 Seata
    local attempt=0
    local max_attempts=20
    
    while [ $attempt -lt $max_attempts ]; do
        if curl -f -s http://localhost:7091/health > /dev/null 2>&1; then
            log_info "Seata 已就绪"
            break
        fi
        ((attempt++))
        log_debug "等待 Seata 启动... ($attempt/$max_attempts)"
        sleep 3
    done
    
    log_info "Seata 服务启动完成"
}

# 启动微服务
start_microservices() {
    log_info "启动微服务..."
    
    # 按依赖顺序启动服务
    docker compose up -d zenith-user-service
    sleep 10
    
    docker compose up -d zenith-api-service zenith-edu-service zenith-article-service
    sleep 10
    
    docker compose up -d zenith-gateway
    sleep 10
    
    log_info "等待微服务启动完成..."
    
    # 检查各微服务健康状态
    local services=("zenith-gateway:9000" "zenith-user-service:9001" "zenith-api-service:9002" "zenith-edu-service:2078" "zenith-article-service:8082")
    
    for service in "${services[@]}"; do
        local service_name=$(echo $service | cut -d: -f1)
        local port=$(echo $service | cut -d: -f2)
        
        log_info "检查 $service_name 服务状态..."
        local attempt=0
        local max_attempts=20
        
        while [ $attempt -lt $max_attempts ]; do
            if curl -f -s http://localhost:$port/actuator/health > /dev/null 2>&1; then
                log_info "$service_name 已就绪"
                break
            fi
            ((attempt++))
            log_debug "等待 $service_name 启动... ($attempt/$max_attempts)"
            sleep 5
        done
        
        if [ $attempt -eq $max_attempts ]; then
            log_warn "$service_name 启动可能存在问题，请检查日志"
        fi
    done
    
    log_info "微服务启动完成"
}

# 显示服务状态
show_status() {
    log_info "显示服务状态..."
    docker compose ps
}

# 显示访问信息
show_access_info() {
    log_info "=== 服务访问信息 ==="
    
    echo ""
    echo "🌐 应用服务:"
    echo "  - API Gateway:     http://localhost:9000"
    echo "  - User Service:    http://localhost:9001"
    echo "  - API Service:     http://localhost:9002"
    echo "  - Edu Service:     http://localhost:2078"
    echo "  - Article Service: http://localhost:8082"
    echo ""
    
    echo "📊 监控面板:"
    echo "  - Prometheus:      http://localhost:9090"
    echo "  - Grafana:         http://localhost:3000 (admin/admin123)"
    echo "  - Sentinel:        http://localhost:8080 (sentinel/sentinel)"
    echo ""
    
    echo "📋 日志分析:"
    echo "  - Kibana:          http://localhost:5601"
    echo "  - Elasticsearch:   http://localhost:9200"
    echo ""
    
    echo "🏗️ 基础设施:"
    echo "  - Nacos:           http://localhost:8848/nacos (nacos/nacos)"
    echo "  - Seata Console:   http://localhost:7091"
    echo "  - MySQL:           localhost:3306 (root/root)"
    echo "  - Redis:           localhost:6379"
    echo ""
    
    echo "📚 API 文档:"
    echo "  - Gateway Docs:    http://localhost:9000/doc.html"
    echo "  - User Service:    http://localhost:9001/doc.html"
    echo "  - API Service:     http://localhost:9002/doc.html"
    echo "  - Edu Service:     http://localhost:2078/doc.html"
    echo "  - Article Service: http://localhost:8082/doc.html"
    echo ""
    
    echo "🔍 健康检查:"
    echo "  docker compose logs -f [service_name]  # 查看服务日志"
    echo "  docker compose exec mysql mysql -uroot -proot  # 连接数据库"
    echo "  docker compose down  # 停止所有服务"
}

# 清理函数
cleanup() {
    log_info "正在清理..."
    docker compose down 2>/dev/null || true
}

# 主函数
main() {
    log_info "开始部署 Zenith Mind Pro 完整环境..."
    log_info "包含：分布式事务(Seata) + 监控告警(Prometheus+Grafana) + 日志管理(ELK)"
    
    # 检查环境
    check_docker
    check_ports
    
    # 准备环境
    create_directories
    
    # 构建和部署
    build_images
    
    # 按顺序启动各种服务
    start_infrastructure
    start_seata
    start_monitoring
    start_logging
    start_microservices
    
    # 显示结果
    show_status
    show_access_info
    
    log_info "🎉 Zenith Mind Pro 完整环境部署成功！"
    log_info "所有服务已启动，可以开始使用了"
}

# 错误处理
trap cleanup EXIT
trap 'log_error "部署过程中发生错误"; cleanup; exit 1' ERR

# 处理命令行参数
case "${1:-}" in
    "stop")
        log_info "停止所有服务..."
        docker compose down
        log_info "所有服务已停止"
        exit 0
        ;;
    "restart")
        log_info "重启所有服务..."
        docker compose down
        main
        ;;
    "logs")
        docker compose logs -f
        ;;
    "status")
        show_status
        show_access_info
        ;;
    *)
        # 默认启动
        main
        ;;
esac